#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdatomic.h>

#include "threadPool.h"

// 定义线程处理任务的结构体
typedef struct task_t
{
    void *pnext;          // 连接下一个任务，队列是由链表构成的
    handler_ptr func_ptr; // 执行的线程池函数指针
    void *args;           // 线程函数的参数
} task_t;

// 定义线程池队列结构体
typedef struct task_queue_s
{
    void *head; // 队列的头部和尾部
    void **tail;
    int block; // 线程池阻塞的标志
    // 锁和条件变量
    pthread_spinlock_t spinlock;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
} task_queue_t;

struct threadpool_s
{
    // 任务队列
    task_queue_t *task_queue;

    // 原子变量（对应cpu指令较少），用于标记线程的退出
    atomic_int quit;

    // 线程数量
    int thread_count;

    // 组织线程的数据结构
    pthread_t *pthreads;
};

//-------------------------------------------任务队列实现-------------------------------------------
//-------------------------------------------任务队列实现-------------------------------------------

// 使用static表示静态成员，只有当前文件可见，其他文件不可见

// 创建队列
static task_queue_t *__task_queue_create()
{
    // 创建资源,使用回滚式编程（还有一种防御式编程，适用于业务代码）
    // 好处是，如果后续失败了，我们能够回收之前没有销毁的空间
    int ret;
    task_queue_t *queue = (task_queue_t *)malloc(sizeof(task_queue_t));
    if (queue)
    {
        ret = pthread_spin_init(&queue->spinlock, 0);
        if (ret == 0)
        {
            // 初始化内部资源,回滚式编程
            ret = pthread_mutex_init(&queue->mutex, NULL);
            if (ret == 0)
            {
                ret = pthread_cond_init(&queue->cond, NULL);
                if (ret == 0)
                {
                    queue->head = NULL;
                    queue->tail = &queue->head;
                    queue->block = 1; // 默认为阻塞
                    return queue;
                }
                pthread_mutex_destroy(&queue->mutex);
            }
            pthread_spin_destroy(&queue->spinlock);
        }
        free(queue);
    }
    return NULL;
}

// 表示线程池是非阻塞的，用于关闭和停止线程池
static void __nonlock(task_queue_t *queue)
{
    pthread_mutex_lock(&queue->mutex);
    queue->block = 0;
    pthread_mutex_unlock(&queue->mutex);

    // 唤醒所有休眠的线程
    pthread_cond_signal(&queue->cond);
}

// 向队列插入任务
// tail为何需要使用二维指针？这样可以不用限定任务的类型，只要任务的起始地址是一个用于连接的next指针。
static inline void *__add_task(task_queue_t *queue, task_t *task) // 生产者
{
    void **link = (void **)task; // link指向了task的next指针
    *link = NULL;                // 将task的next指针设置为NULL

    // 注意需要保护临界变量
    pthread_spin_lock(&queue->spinlock);
    *(queue->tail) /* 就是queue->tail->next*/ = link;
    queue->tail = link; // 将task设置为尾部
    pthread_spin_unlock(&queue->spinlock);

    // 唤醒线程池中的线程进行任务处理
    pthread_cond_broadcast(&queue->cond);
}

// 队列取出任务
static inline void *__pop_task(task_queue_t *queue) // 消费者
{
    pthread_spin_lock(&queue->spinlock);
    if (queue->head == NULL)
    {
        pthread_spin_unlock(&queue->spinlock);

        return NULL;
    }

    // 线程池线程拿到任务
    task_t *task = ((task_t *)queue->head);
    void **link = (void **)task;
    queue->head = *link;

    // 拿取数据后，若队列为空，则需要将队尾重新指向队首的next
    if (queue->head == NULL)
    {
        queue->tail = &queue->head;
    }
    pthread_spin_unlock(&queue->spinlock);
    return task;
}

// 获取队列任务
static inline void *__get_task(task_queue_t *queue)
{
    task_t *task;
    while ((task = __pop_task(queue)) == NULL)
    {
        pthread_mutex_lock(&queue->mutex);

        if (queue->block == 0) // 非阻塞，返回NULL;
        {
            pthread_mutex_unlock(&queue->mutex);
            return NULL;
        }

        // 如果线程是阻塞的，当前线程在条件变量下等待add函数唤醒
        pthread_cond_wait(&queue->cond, &queue->mutex);

        pthread_mutex_unlock(&queue->mutex);
        // 到这里，说明生产者函数唤醒了消费者线程，可以让消费者线程处理任务了

        // 然后重新进入循环pop任务，避免虚假唤醒
    }
    return task;
}

// 队列的销毁
static task_queue_t *__task_queue_destory(task_queue_t *queue)
{
    // 销毁队列中的任务
    task_t *task;
    while ((task == __pop_task(queue)))
    {
        free(task);
        task = NULL;
    }

    // 销毁锁和条件变量
    pthread_spin_destroy(&queue->spinlock);
    pthread_mutex_destroy(&queue->mutex);
    pthread_cond_destroy(&queue->cond);

    // 销毁队列
    free(queue);
    queue = NULL;
}

//-------------------------------------------任务队列实现-------------------------------------------
//-------------------------------------------任务队列实现-------------------------------------------

//-------------------------------------------单个线程实现-------------------------------------------
//-------------------------------------------单个线程实现-------------------------------------------

// 线程池入口函数
static void *__thread_worker(void *args)
{
    // args是线程池指针
    threadpool_t *threadpool = (threadpool_t *)args;
    task_t *task; // 包含了该线程的执行函数和参数

    while (atomic_load(&threadpool->quit) == 0)
    {
        task = (task_t *)__get_task(threadpool->task_queue);
        if (task == NULL) // 获取任务失败
            break;

        // 执行处理任务的函数
        handler_ptr func = task->func_ptr;
        void *ctx = task->args;
        free(task); // 防止内存泄漏

        func(ctx);
    }
    return NULL;
}

// 暂停并等待所有线程
static void __threads_terminate(threadpool_t *pool)
{
    atomic_store(&pool->quit, 1);
    __nonlock(pool->task_queue); // 唤醒所有休眠线程

    int i = 0;
    for (i = 0; i < pool->thread_count; i++)
    {
        pthread_join(pool->pthreads[i], NULL);
    }
}

// 创建所有的线程
static int __thread_create(threadpool_t *threadpool, size_t thread_count)
{
    pthread_attr_t attr;
    int ret = 0;
    ret = pthread_attr_init(&attr);

    if (ret == 0)
    {
        // 开辟管理线程的数据结构/数组
        threadpool->pthreads = (pthread_t *)malloc(sizeof(pthread_t *) * thread_count);

        // 开始创建线程
        int i = 0;
        for (i = 0; i < thread_count; i++)
        {
            if (pthread_create(&threadpool->pthreads[i], &attr, __thread_worker, (void *)threadpool) < 0)
            {
                printf("__thread_create pthread_create error");
                break;
            }
        }

        threadpool->thread_count = i;
        if (i == thread_count) // 说明所有线程创建成功
            return 0;

        // 线程创建失败,销毁所有数据
        pthread_attr_destroy(&attr);

        // 暂停等待所有线程
        __threads_terminate(threadpool);

        free(threadpool->pthreads);
        threadpool->pthreads = NULL;
    }
    return -1;
}

//-------------------------------------------单个线程实现-------------------------------------------
//-------------------------------------------单个线程实现-------------------------------------------

//-------------------------------------------线程池实现-------------------------------------------
//-------------------------------------------线程池实现-------------------------------------------

// 创造线程池
threadpool_t *threadpool_create(int thread_count)
{
    threadpool_t *pool = (threadpool_t *)malloc(sizeof(threadpool_t));
    if (pool != NULL)
    {
        task_queue_t *task_queue = __task_queue_create();
        if (task_queue != NULL)
        {
            pool->task_queue = task_queue;
            atomic_init(&pool->quit, 0);
            if (__thread_create(pool, thread_count) == 0)
            {
                return pool;
            }

            free(task_queue);
            task_queue = NULL;
        }
        free(pool);
        pool = NULL;
    }
    printf("threadpool_create error\n");
    return NULL;
}

// 暂停线程池
void threadpool_terminate(threadpool_t *pool)
{
    atomic_store(&pool->quit, 1);
    __nonlock(pool->task_queue);
}

// 让任务func和参数args交给线程池poll执行
int threadpool_post(threadpool_t *pool, handler_ptr func, void *args)
{
    if (atomic_load(&pool->quit) == 1)
    {
        // 说明线程池退出
        return -1;
    }
    task_t *task = (task_t *)malloc(sizeof(task_t));

    if (task == NULL)
        return -1;

    // 构建task
    task->func_ptr = func;
    task->args = args;
    task->pnext = NULL;

    // 添加task到任务队列

    __add_task(pool->task_queue, task);
    return 0;
}

// 测试，让所有线程安全退出
void threadpool_waitdown(threadpool_t *pool)
{
    int i = 0;
    for (i = 0; i < pool->thread_count; i++)
    {
        pthread_join(pool->pthreads[i], NULL);
    }

    free(pool->pthreads);
    free(pool);
}

//-------------------------------------------线程池实现-------------------------------------------
//-------------------------------------------线程池实现-------------------------------------------
